const Web3 = require('web3');
const providers = require('../config.json');
const pg = require('../db/db');
const { logger } = require('./logger');

let web3;
/**
 * test only
 */
let tx = async () => {
    let from = await web3.eth.getAccounts();
    let coinbase = await web3.eth.getCoinbase()
    let balance = await web3.eth.getBalance(coinbase);
    web3.eth.sendTransaction({
        from: coinbase,
        to: from[1],//'0x44aac912ea05288077a5f9b7fdef163c84624e00',
        value: web3.utils.toWei('1', 'wei'),
        gas: 672197,
        gasPrice: 20000000000,
        // nonce:323424
    })
        .then(data => logger.info('data:==>', data))
        .catch(err => logger.error('err:==>', err));
}


// init web3 
let intitWeb3 = async () => {
    try {
        web3 = undefined;
        if (typeof web3 !== 'undefined') {
            web3 = new Web3(web3.currentProvider);
        } else {
            // set the provider you want from Web3.providers
            web3 = new Web3(new Web3.providers.WebsocketProvider(providers.providers))
        }

        //write DB 
        blockToDB();

    } catch (error) {
        logger.error("web3 init error===>", error);
    }
}
/**
 * test insert into db
 */
let testObj = {
    difficulty: 131264,
    extraData: "0xda8301080b846765746888676f312e31302e328777696e646f7773",
    gasLimit: 3160033,
    gasUsed: 21464,
    hash: "0x87c63b99f9b2699434b8282cb7c93fe8fa19d54b22fb35363f66467f8b79cd5d",
    logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    miner: "0x089021de39b82509f6c00dabe32cc3b618f6f802",
    mixHash: "0xda0c26597a4fc59385ea717277c0b503864ec2e90b3b36660999ed6ec6cd08ae",
    nonce: "0x1582136f7664e75c",
    number: 6,
    parentHash: "0x7c35645944c3a7710235261ec4b169c32e147d8b0c46991b1d57d3094dedd208",
    receiptsRoot: "0x1329829d0a04a2d093d5fbb9052f7924b16de8a465651c8e79a060efc3b7a368",
    sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    size: 675,
    stateRoot: "0xee7ba3765c1db08b628ffc99cb36aea1ac67b46d4955d17e41a56c581e61f228",
    timestamp: 1530523742,
    totalDifficulty: 918016,
    transactions: ["0x80915aa8de673a65ea31e7c7b999df1e2bcbce81405a35636fdf553ce21e32fd", "0xbb4bb1b4fa7f921618cf598d33109df4951b645d2e7d04293d400ccbd4155utf"],
    transactionsRoot: "0xac01915469a3392e2473ad542a6f13fbebc47ee801ed6ea67bb05aeed43cb993",
    uncles: []
}

let logs = {
    "transactionHash": "0x80915aa8de673a65ea31e7c7b999df1e2bcbce81405a35636fdf553ce21e32fd",
    "transactionIndex": 0,
    "blockHash": "0x19c19a8503d53fd85d8c20c5dd51dfcbaee8021cdc9d48a2d2e4e159a8581147",
    "blockNumber": 19,
    "gasUsed": 36633,
    "cumulativeGasUsed": 36633,
    "contractAddress": null,
    "logs": [
        {
            "logIndex": 0,
            "transactionIndex": 0,
            "transactionHash": "0x80915aa8de673a65ea31e7c7b999df1e2bcbce81405a35636fdf553ce21e32fd",
            "blockHash": "0x19c19a8503d53fd85d8c20c5dd51dfcbaee8021cdc9d48a2d2e4e159a8581147",
            "blockNumber": 19,
            "address": "0x2785a633a7bf19a50321e2e8ffc5f854ac1eafab",
            "data": "0x00000000000000000000000000000000000000000000000000000000000004bc",
            "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000c0ab283acacd1fe73b2f0d19d383a90aaa1cc99f", "0x000000000000000000000000c0ab283acacd1fe73b2f0d19d383a90aaa1cc99f"],
            "type": "mined"
        }
    ],
    "status": "0x01",
    "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000010000000000000000000000000000000000008000000000000000000000000000000000002000000000000000000000000000000000000000800000000000000000010000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000"
}
// block info to wirte DB 
let blockToDB = async () => {
    try {
        // listening block
        web3.eth.subscribe('newBlockHeaders', async (err, data) => {
            if (!err) {
                web3.eth.getBlock(data.number, async (error, result) => {
                    // result = testObj;// test only
                    if (!error) {
                        logger.info(`block-number==>${result.number}`, `result===>${JSON.stringify(result)}`);
                        let blockObj = await pg.any(`SELECT * FROM ethblock WHERE ethblock."number" = '${data.number}'`);
                        if (blockObj.length == 0) {
                            await pg.none(wirteBlocks(result));
                            if (result.transactions.length != 0) {
                                // TODO
                                wirteTransactions(result.transactions);
                            }
                        }
                    } else {
                        logger.error('subscribe newBlockHeaders：', error);
                    }
                })
            }

            // TODO write DB  test table
            // return await pg.none(wirteBlocks);
        });
    } catch (error) {
        logger.error("web3 init error===>", error);
    }
}

let wirteBlocks = (result) => {
    let sql = `INSERT INTO ethblock(
        difficulty, "extraData", "gasLimit", "gasUsed", hash, "logsBloom", miner, "mixHash", nonce, "number", 
        "parentHash", "receiptsRoot", "sha3Uncles", size, "stateRoot", "timestamp", "totalDifficulty", transactions, "transactionsRoot", uncles)
        VALUES ('${result.difficulty}','${result.extraData}',${result.gasLimit},${result.gasUsed},'${result.hash}','${result.logsBloom}','${result.miner}',
            '${result.mixHash}','${result.nonce}',${result.number},'${result.parentHash}',
            '${result.receiptsRoot}','${result.sha3Uncles}',${result.size},'${result.stateRoot}','${result.timestamp}',
            '${result.totalDifficulty}','{${result.transactions}}','${result.transactionsRoot}','{${result.uncles}}');`;
    return sql;
}


/**
 * test sql
 * 
 * INSERT INTO public.ethblock(difficulty, "extraData", "gasLimit", "gasUsed", hash, "logsBloom", miner, "mixHash", nonce, "number", "parentHash", "receiptsRoot", "sha3Uncles", size, "stateRoot", "timestamp", "totalDifficulty", transactions, "transactionsRoot", uncles)
	VALUES (131264, '0xda8301080b846765746888676f312e31302e328777696e646f7773', 3160033, 21464,
			'0x87c63b99f9b2699434b8282cb7c93fe8fa19d54b22fb35363f66467f8b79cd5d', 
			'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
			'0x089021de39b82509f6c00dabe32cc3b618f6f802', '0xda0c26597a4fc59385ea717277c0b503864ec2e90b3b36660999ed6ec6cd08ae',
			'0x1582136f7664e75c', 6, '0x7c35645944c3a7710235261ec4b169c32e147d8b0c46991b1d57d3094dedd208', '0x1329829d0a04a2d093d5fbb9052f7924b16de8a465651c8e79a060efc3b7a368',
			'0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', 675, '0xee7ba3765c1db08b628ffc99cb36aea1ac67b46d4955d17e41a56c581e61f228', '1530523742',
			'918016', '{0xbb4bb1b4fa7f921618cf598d33109df4951b645d2e7d04293d400ccbd4153ed4,0xbb4bb1b4fa7f921618cf598d33109df4951b645d2e7d04293d400ccbd4153ed1}',
			'0xac01915469a3392e2473ad542a6f13fbebc47ee801ed6ea67bb05aeed43cb993','{0xac01915469a3392e2473ad542a6f13fbebc47ee801ed6ea67bb05aeed43cb993}');

 *INSERT INTO ethtransactions( "transactionHash", "transactionIndex", "blockHash", "blockNumber", "gasUsed", "cumulativeGasUsed", "contractAddress", status, "logsBloom")
	VALUES ('0x80915aa8de673a65ea31e7c7b999df1e2bcbce81405a35636fdf553ce21e32fd',0,'0x19c19a8503d53fd85d8c20c5dd51dfcbaee8021cdc9d48a2d2e4e159a8581147',9,
		   36633,36633,null,'0x01','0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000010000000000000000000000000000000000008000000000000000000000000000000000002000000000000000000000000000000000000000800000000000000000010000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000');
 
 
 INSERT INTO ethlogs("logIndex", "transactionIndex", "transactionHash", "blockHash", "blockNumber", address, data, topics, type)
	VALUES (0, 0, '0x80915aa8de673a65ea31e7c7b999df1e2bcbce81405a35636fdf553ce21e32fd', '0x19c19a8503d53fd85d8c20c5dd51dfcbaee8021cdc9d48a2d2e4e159a8581147'
			,19,'0x2785a633a7bf19a50321e2e8ffc5f854ac1eafab', '0x00000000000000000000000000000000000000000000000000000000000004bc', '{"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000c0ab283acacd1fe73b2f0d19d383a90aaa1cc99f","0x000000000000000000000000c0ab283acacd1fe73b2f0d19d383a90aaa1cc99f"
			}', 'mined');
 
* 
* 
*/
let wirteTransactions = (txs) => {
    for (let i = 0; i < txs.length; i++) {

        web3.eth.getTransaction(txs[i], async (err, data) => {
            logger.info('getTransaction:=====>', data);
            let transactionsObj = await pg.any(`SELECT * FROM ethtransactions WHERE ethtransactions."transactionHash" = '${data.hash}'`);
            if (transactionsObj.length == 0) {
                getTransactionReceipt(data);
            }
        });

        // web3.eth.getTransactionReceipt(txs[i], (err, sets) => {
        //     // sets = logs;//test only
        //     let sql = `INSERT INTO ethtransactions( "transactionHash", "transactionIndex", "blockHash", "blockNumber", "gasUsed", "cumulativeGasUsed", "contractAddress", status, "logsBloom")
        //                 VALUES ('${sets.transactionHash}',${sets.transactionIndex},'${sets.blockHash}',
        //                 ${sets.blockNumber},${sets.gasUsed},${sets.cumulativeGasUsed},
        //                 ${sets.contractAddress},'${sets.status}','${sets.logsBloom}');`;
        //     pg.none(sql);
        //     if (sets.logs.length != 0) {
        //         for (let j in sets.logs) {

        //             let sql = `INSERT INTO ethlogs("logIndex", "transactionIndex", "transactionHash", "blockHash", "blockNumber", address, data, topics, type)
        //                 VALUES (${sets.logs[j].logIndex}, ${sets.logs[j].transactionIndex}, '${sets.logs[j].transactionHash}', '${sets.logs[j].blockHash}',
        //                 ${sets.logs[j].blockNumber},'${sets.logs[j].address}', '${sets.logs[j].data}', '{${sets.logs[j].topics}}', '${sets.logs[j].type}');`;
        //             pg.none(sql);
        //         }
        //     }
        // })
    }
}

let getTransactionReceipt = (data) => {
    web3.eth.getTransactionReceipt(data.hash, async (err, sets) => {
        logger.info('getTransactionReceipt:==>', sets);
        let sql = `INSERT INTO ethtransactions( "transactionHash", "transactionIndex", "blockHash", "blockNumber", "gasUsed", "cumulativeGasUsed", "contractAddress", status,
        "from", gas, "gasPrice", hash, input, nonce, "to", value)
        VALUES ('${sets.transactionHash}',${sets.transactionIndex},'${sets.blockHash}', ${sets.blockNumber},${sets.gasUsed},${sets.cumulativeGasUsed},
        '${sets.contractAddress}','${sets.status}','${data.from}','${data.gas}','${data.gasPrice}','${data.hash}','${data.input}','${data.nonce}','${data.to}','${data.value}');`;
        await pg.none(sql);
        if (sets.logs.length != 0) {
            for (let j in sets.logs) {
                /**####################################################调整logs表结构预留代码###########################################################################*/
                // let sql = `INSERT INTO ethlogs("logIndex", "transactionIndex", "transactionHash", "blockHash", "blockNumber", address, data, topics, type)
                //         VALUES (${sets.logs[j].logIndex}, ${sets.logs[j].transactionIndex}, '${sets.logs[j].transactionHash}', '${sets.logs[j].blockHash}',
                //         ${sets.logs[j].blockNumber},'${sets.logs[j].address}', '${sets.logs[j].data}', '{${sets.logs[j].topics}}', '${sets.logs[j].type}');`;
                // await pg.none(sql);
                /**####################################################调整logs表结构预留代码###########################################################################*/
                if (sets.logs[j].topics.length != 0) {
                    let sql = getTopic(sets.logs[j]);
                    await pg.none(sql);
                }
            }
        }
    })
}
let getTopic = (obj) => {
    let sql_filed = `INSERT INTO ethlogs("logIndex", "transactionIndex", "transactionHash", "blockHash", "blockNumber", address, data,type `
    let sql_value = `VALUES (${obj.logIndex}, ${obj.transactionIndex}, '${obj.transactionHash}', '${obj.blockHash}', ${obj.blockNumber},'${obj.address}', '${obj.data}', '${obj.type}'`;

    obj.topics.forEach((element, index) => {
        sql_filed += `, topics_${index}`;
        sql_value += ` , '${element}' `;
    });
    sql_filed += `) `;
    sql_value += `);`;
    return sql_filed + sql_value;
}
let isCN = () => {
    return new Promise((resolve, reject) => {
        web3.eth.net.isListening((err, result) => {
            if (result) {
                resolve(true)
            } else {
                resolve(false);
            }
        });
    })
}
// check listen eth.net 
// setInterval(async () => {
//     if (web3 == undefined) intitWeb3();
//     let isCn = await isCN();

//     // tx(); //test only
//     if (!isCn) intitWeb3();
//     logger.info('web3.net.listening==>', isCn);

// }, 1000);

//TODO
// getTransanctions by transactionHash
let getTransanctions = async (transactionHash) => {
    try {
        // TODO
        // getTransanctions by address
        return await pg.any(`SELECT * FROM ethtransactions WHERE ethtransactions."transactionHash" = '${transactionHash}'`);
        // success

    } catch (error) {
        logger.error("getTransanctions error===>", error);
    }
}

module.exports = { getTransanctions }